#ifndef BTRANS_WORKER_H
#define BTRANS_WORKER_H

#include <QtWebKit>
#include <QApplication>
#include <boost/program_options.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <QVector>

#include "WebBrowser.h"
#include "Translate.h"

namespace po = boost::program_options;

class Worker : public QObject {
  Q_OBJECT
signals:
  void nextUrl();
protected:
  po::variables_map& vm;
  WebBrowser& web;
  QNetworkAccessManager *manager;
  boost::posix_time::ptime time_start, time_end;
  boost::posix_time::time_duration duration;
  std::string infn, outfn;
  QVector<QString> list;
  QVector<QString> pages;
  QVector<int> status;
  int n_current;
public:
  explicit Worker(po::variables_map& vm_, WebBrowser& web_, QObject *parent = 0) : QObject(parent), vm(vm_), web(web_)
  {
    manager = new QNetworkAccessManager(this);
  }
public slots:
  void do_url() 
  {
    time_start = boost::posix_time::microsec_clock::local_time();
    std::string inurl = vm["url"].as<std::string>();
    outfn = vm["output"].as<std::string>();
    std::cout << "process url " << inurl << " output to " << outfn << std::endl;

    QUrl url = QUrl::fromUserInput(QString::fromStdString(inurl));
    QTextStream(stdout) << "url = " << url.toString() << endl;

    connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(urlFinished(QNetworkReply*)));
    manager->get(QNetworkRequest(url));
  }

  void do_dumptext() {
    infn = vm["input"].as<std::string>();
    outfn = vm["output"].as<std::string>();
    std::cout << "process input = " << infn << " output = " << outfn << std::endl;
    
    QFile input(QString::fromStdString(infn));
    if (!input.open(QIODevice::ReadOnly | QIODevice::Text)) {
      std::cerr << "cannot open file " << infn << std::endl;
      return;
    }
    
    QTextStream inputStream(&input);
    //connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(getPageFinished(QNetworkReply*)));
    list.clear();
    while (!inputStream.atEnd()) {
      QString line = inputStream.readLine();
      if (line.isEmpty()) break;
      QUrl url = QUrl::fromUserInput(line);
      if (vm.count("prefix") && line.indexOf(QString::fromStdString(vm["prefix"].as<std::string>())) == -1) continue;
      //QTextStream(stdout) << "get url = " << url.toString() << endl;
      //manager->get(QNetworkRequest(url));
      list.push_back(url.toString());
    }
    pages = QVector<QString>(list.size());
    status = QVector<int>(list.size(), 0);

    Translator::loadDictionaries();
    n_current = 0;
    connect(&web, SIGNAL(loadFinished(bool)), this, SLOT(savePage(bool)));
    sendUrl();
  }

  void sendUrl() {
    QTextStream(stdout) << "n = " << n_current << " get " << list[n_current] << endl;
    web.load(QUrl(list[n_current]));
  }

  void savePage(bool ok) {
    if (!ok) {
      QTextStream(stdout) << "error" << endl;
      pages[n_current] = "ERROR";
    }
    else {
      QTextStream(stdout) << "received " << list[n_current] << endl;
      pages[n_current] = Translator::translateText(web.page()->mainFrame()->toPlainText());
    }
    status[n_current++] = 1;

    if (n_current < list.size())
      sendUrl();
    else {
      QTextStream(stdout) << "all done." << endl;
      dumptext();
      QApplication::exit();
    }
  }

  void urlFinished(QNetworkReply* reply) {
    reply->deleteLater();
    QTextStream(stdout) << "received " << reply->url().toString() << endl;
    if (reply->error() != QNetworkReply::NoError) {
      QTextStream(stdout) << "error " << reply->errorString() << endl;
      return;
    }
    
    QTextStream input(reply);
    input.setCodec("UTF-8");
    QString page = input.readAll();
    //QTextStream(stdout) << "content = " << endl << page << endl;
    parseAllUrl(reply->url(), page);

    time_end = boost::posix_time::microsec_clock::local_time();
    duration = time_end - time_start;
    std::cout << "Duration = " << duration << std::endl;
    QCoreApplication::exit();
  }

  void getPageFinished(QNetworkReply* reply) {
    reply->deleteLater();
    QTextStream(stdout) << "received " << reply->url().toString() << endl;
    if (reply->error() != QNetworkReply::NoError) {
      QTextStream(stdout) << "error " << reply->errorString() << endl;
      return;
    }
    
    QByteArray ba = reply->readAll();
    QTextCodec *codec = QTextCodec::codecForHtml(ba);
    //QTextStream(stdout) << "codec=" << codec->name() << endl;
    QTextStream input(ba);
    input.setCodec(codec);
    QString page = input.readAll();
    QString url = reply->url().toString();

    for (int i = 0; i < list.size(); i++) 
      if (url == list[i]) {
	//QTextStream cout(stdout);
	//cout.setCodec("UTF-");
	//cout << page << endl;
	//web.page()->mainFrame()->setHtml(page, QUrl(url));
	pages[i] = page;//web.page()->mainFrame()->toPlainText();
	status[i] = 1;
	std::cout << "i=" << i << std::endl;
	break;
      }

    bool all_done = true;
    for (int i = 0; i < list.size(); i++) 
      if (status[i] == 0) {
	all_done = false;
	break;
      }
    if (all_done || !all_done) {
      dumptext();
      QCoreApplication::exit();
      std::cout << "all done." << std::endl;
    }
    //QTextStream(stdout) << "content = " << endl << page << endl;
  }

 protected:
  void parseAllUrl(const QUrl& url, const QString& page)
  {
    QRegExp rx("(a\\s+href\\s*\\=\\s*\\\"[^\\\"]*\\\")", Qt::CaseInsensitive);
    //QRegExp rx("(a\\s+href\\s*\\=\\s*\\\"[^\\\"]*\\\"|a\\s+href\\s*\\=\\s*\\\\\\\"[^\\\"]*\\\\\\\")");
    QFile f(QString::fromStdString(outfn));
    if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) {
      std::cerr << "cannot open file " << outfn << std::endl;
      return;
    }
    QTextStream output(&f);
    
    int pos = 0;
    QStringList list;
    while ((pos = rx.indexIn(page, pos)) != -1) {
      QString cap = rx.cap(1);
      pos += rx.matchedLength();
      int urlPos = cap.indexOf("\"");
      cap = cap.mid(urlPos+1, cap.length()-urlPos-2);
      if (cap.indexOf("http://") == -1) {
	QUrl relUrl = url.resolved(cap);
	cap = relUrl.toString();
      }
      else {
	cap = QUrl::fromUserInput(cap).toString();
      }
      //QTextStream(stdout) << cap << endl;
      //output << cap << endl;
      list << cap;
    }
    list.removeDuplicates();

    Q_FOREACH(const QString& cap, list) {
      QTextStream(stdout) << cap << endl;
      output << cap << endl;
    }    
  }

  void dumptext() 
  {
    QFile f(QString::fromStdString(outfn));
    if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) {
      std::cerr << "cannot open file " << outfn << std::endl;
      return;
    }
    QTextStream output(&f);
    //output.setCodec("UTF-8");
    for (int i = 0; i < list.size(); i++) if (status[i] == 1) {
      QTextStream(stdout) << "printing " << i << " status = " << status[i] << " at " << list[i] << endl;

      output << "==================================================" << endl;
      output << "count = " << i << endl;
      output << "url = " << list[i] << endl << endl;
      output << pages[i] << endl << endl;
    }
  }

  QString stripText(const QString& htmlString) 
  {
    QXmlStreamReader xml(htmlString);
    QString textString;
    while (!xml.atEnd()) {
      QXmlStreamReader::TokenType token = xml.readNext();
      QTextStream(stdout) << "token=" << token << endl;
      QTextStream(stdout) << "data=" << xml.text().toString() << endl;      
      if ( token == QXmlStreamReader::Characters ) {
        textString += xml.text();
	textString += "\n";
      }
    }
    if (xml.hasError()) {
      QTextStream(stdout) << "error parsing XML" << endl;
    }
    return textString;
  }
  
};

#endif
